﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.Remoting.Lifetime;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Crawler.ApplicationServices;
using Crawler.Domain;
using Crawler.Domain.DataEntities;
using Crawler.Domain.DataEntities.Crawling;
using Crawler.Domain.Sources;
using Crawler.DomainServices.DataServices;
using Crawler.DomainServices.Processors;
using log4net;

namespace Crawler.ContentProcessors
{
	class TorrentContentProcessor	  :ITorrentContentProcessor
	{
		private readonly IProcessorsConfiguration _configuration;
		private readonly ICrawlingSessionRepository _sessionRepository;
		private readonly ISourceContentRepository _contentRepository;
		private readonly IPageContentProcessorProvider _processorProvider;
		private static readonly ILog Logger = LogManager.GetLogger("AppLogger");
		public TorrentContentProcessor(IProcessorsConfiguration configuration, ICrawlingSessionRepository sessionRepository, 
		ISourceContentRepository sourceContentRepository, IPageContentProcessorProvider contentProcessorProvider)
		{
			_configuration = configuration;
			_sessionRepository = sessionRepository;
			_contentRepository = sourceContentRepository;
			_processorProvider = contentProcessorProvider;
		}

		public void Start(string sessionId, CancellationTokenSource cts)
		{
			CrawlingSession session= _sessionRepository.Get(sessionId);
			if(session==null) return;

			ProccessPages(session,cts);
		}


		private void ProccessPages(CrawlingSession session, CancellationTokenSource cts)
		{

			int sizePage = _configuration.MaxThreads;

			var tasks = new List<Task>();
			List<RawPageCrawlInfo> sources;
			do
			{
				tasks.Clear();
				sources = _contentRepository.GetProccessablePage(ProccessablePageType.MovieFile, 1,
					session, sizePage).ToList();
				Logger.InfoFormat("Processing SessionId:{0} Pages at a time:{1} From Id:{2}", session.SessionId, sources.Count(),sources.Any()? sources.First().Id:int.MinValue);
				foreach (var page in sources)
				{
					RawPageCrawlInfo page1 = page;
					tasks.Add(Task.Factory.StartNew(() => ProccessPage(session, page1)));
				}
				Task.WaitAll(tasks.ToArray(), cts.Token);
			} while (sources != null && sources.Any());
			session.PagesProcessedCompleted = true;
			_sessionRepository.Save(session);
		}

		private void ProccessPage(CrawlingSession sessionInfo, RawPageCrawlInfo page)
		{
			var html = File.ReadAllText(page.FilePath);

			var pageContentProcessor = _processorProvider.Get(EnumsMapper.GetMoviePageSource(sessionInfo.Source));
			var src = new MovieProcessableSource(sessionInfo.Source, sessionInfo.SessionId, page.FromUrl,
				html);
			pageContentProcessor.ProcessPageContent(src);
					
			page.Processed = true;
			page.ProcessedDateTime = DateTime.UtcNow;
			_contentRepository.Save(page);

			sessionInfo.IncrementPagesProcessed();
		}

	}
}
